package com.google.code.lf.commons.rules.service;

import java.rmi.RemoteException;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

import javax.rules.InvalidRuleSessionException;
import javax.rules.StatelessRuleSession;

import org.springmodules.jsr94.core.Jsr94RuleSupport;
import org.springmodules.jsr94.support.StatelessRuleSessionCallback;

import com.google.code.lf.gfm.service.GrisbiRuleGlobals;

/**
 * Classe mère pour les implémentations avec <a href="http://www.jboss.org/drools/">drools</a> de règles de l'application.
 * <br/>Propose des méthodes utilitaires pour l'éxécution des règles.
 *
 * @author gael.lorent-fonfrede
 *
 * @param <T>
 */
public abstract class AbstractRuleService<T> extends Jsr94RuleSupport {
	/**
	 * Déclenche l'exécution d'une règle.
	 * <br/>L'exécution est de type <em>stateless</em>, c-à-d sans état.
	 * <br/>Un objet est fourni à la règle (état d'entrée), qui raisonne sur cette base.
	 * <br/>La méthode retourne cet objet modifié (état de sortie).
	 *
	 * @param ruleName Nom de la règle à déclencher (en pratique, nom du bean Spring de la ruleSource).
	 * @param input L'objet d'entrée.
	 * @param globals La map des variables globales à utiliser dans les règles (attention, valable uniquement pour le cas de l'api <a href="http://http://www.jboss.org/drools">drools</a>).
	 * <br/>&nbsp;Ces variables sont à considérer comme des pointeurs vers des instances de services externes à drools (ex: session hibernate, mail, logger, etc), utilisables dans les règles.
	 * <br/>&nbsp;NB: les clés de la map dans le code appelant et dans les définitions de variables globales des fichiers de règles doivent être identiques : utiliser {@link GrisbiRuleGlobals}.
	 * @return Le premier objet de la liste d'objet d'entrée modifiée.
	 * 
	 * @see StatelessRuleSession.
	 */
	@SuppressWarnings("unchecked")
	protected T executeRules(final String ruleName, final T input, final Map<String, Object> globals) {
		// Exécution stateless de la règle sur la base des données fournies en entrée
		final List<T> output = (List<T>) getTemplate().executeStateless(ruleName, globals, new StatelessRuleSessionCallback() {
			/* (non-Javadoc)
			 * @see org.springmodules.jsr94.support.StatelessRuleSessionCallback#execute(javax.rules.StatelessRuleSession)
			 */
			public Object execute(final StatelessRuleSession session) throws InvalidRuleSessionException, RemoteException {
				// Exécution des règles en fournissant l'objet d'entrée en tant que liste
				return session.executeRules(Arrays.asList(input));
			}
		});
		// On retourne le premier objet de la liste d'objets suite à l'exécution des règles
		return output.get(0);
	}

	/**
	 * Déclenche l'exécution d'une règle.
	 * <br/>L'exécution est de type <em>stateless</em>, c-à-d sans état.
	 * <br/>Une liste d'objets est fournie à la règle (état d'entrée), qui raisonne sur cette base.
	 * <br/>La méthode retourne cette liste d'objets modifiée (état de sortie).
	 *
	 * @param ruleName Nom de la règle à déclencher (en pratique, nom du bean Spring de la ruleSource).
	 * @param input Liste d'objets d'entrée.
	 * @param globals La map des variables globales à utiliser dans les règles (attention, valable uniquement pour le cas de l'api <a href="http://http://www.jboss.org/drools">drools</a>).
	 * <br/>&nbsp;Ces variables sont à considérer comme des pointeurs vers des instances de services externes à drools (ex: session hibernate, mail, logger, etc), utilisables dans les règles.
	 * <br/>&nbsp;NB: les clés de la map dans le code appelant et dans les définitions de variables globales des fichiers de règles doivent être identiques : utiliser {@link GrisbiRuleGlobals}.
	 * @return La liste d'objet d'entrée modifiée.
	 * 
	 * @see StatelessRuleSession.
	 */
	@SuppressWarnings("unchecked")
	protected List<Object> executeRules(final String ruleName, final List<Object> input, final Map<String, Object> globals) {
		// Exécution stateless de la règle sur la base de la liste d'objets fournie
		final List<Object> output = (List<Object>) getTemplate().executeStateless(ruleName, globals, new StatelessRuleSessionCallback() {
			/* (non-Javadoc)
			 * @see org.springmodules.jsr94.support.StatelessRuleSessionCallback#execute(javax.rules.StatelessRuleSession)
			 */
			public Object execute(final StatelessRuleSession session) throws InvalidRuleSessionException, RemoteException {
				// Exécution des règles en fournissant une liste d'objets en entrée
				return session.executeRules(input);
			}
		});
		// On retourne la liste d'objets suite à l'exécution des règles
		return output;
	}
}
